﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Text;
using ParieurPro.DAL.DatabaseModel;
using ParieurPro.DAL.Exception;
using System.Data.SqlClient;

namespace ParieurPro.DAL
{
    /// <summary>
    /// Classe de gestion des matchs
    /// Un match est constitué d'un 
    ///     - identifiant
    ///     - un numéro de journée
    ///     - un identifiant d'équipe à domicile
    ///     - un identifiant d'équipe à l'extérieure
    ///     - le score de l'équipe à domicile
    ///     - le score de l'équipe à l'extérieure
    ///     - une prédiction de score pour l'équipe à domicile
    ///     - une prédiction de score pour l'équipe à l'extérieure
    /// </summary>
    [Serializable()]
    public class MatchObject
    {
        #region Attributes
        private int _matchId;
        private int _teamAwayId;
        private int _teamHomeId;
        private byte? _teamHomeScore;
        private byte? _teamAwayScore;
        private int _dayNumber;
        private byte? _teamHomeBetScore;
        private byte? _teamAwayBetScore;
        private string _displayName;
        #endregion

        #region Properties

        /// <summary>
        /// Identifiant unique du match
        /// </summary>
        [Key()]
        [DataMemberAttribute()]
        public int MatchId
        {
            get { return _matchId; }
            set { _matchId = value; }
        }

        /// <summary>
        /// Identifiant unique de l'équipe à l'extérieur
        /// </summary>
        [DataMemberAttribute()]
        public int TeamAwayId
        {
            get { return _teamAwayId; }
            set { _teamAwayId = value; }
        }

        /// <summary>
        /// Identifiant unique de l'équipe à domicile
        /// </summary>
        [DataMemberAttribute()]
        public int TeamHomeId
        {
            get { return _teamHomeId; }
            set { _teamHomeId = value; }
        }

        /// <summary>
        /// Score de l'équipe à domicile
        /// </summary>
        [DataMemberAttribute()]
        public byte? TeamHomeScore
        {
            get { return _teamHomeScore; }
            set { _teamHomeScore = value; }
        }

        /// <summary>
        /// Score de l'équipe à l'extérieur
        /// </summary>
        [DataMemberAttribute()]
        public byte? TeamAwayScore
        {
            get { return _teamAwayScore; }
            set { _teamAwayScore = value; }
        }

        /// <summary>
        /// Numéro de la journée à laquelle appartient le match
        /// </summary>
        [DataMemberAttribute()]
        public int DayNumber
        {
            get { return _dayNumber; }
            set { _dayNumber = value; }
        }

        /// <summary>
        /// Indique si c'est le match du jour
        /// </summary>
        [DataMemberAttribute()]
        public string DisplayName
        {
            get { return _displayName; }
            set { _displayName = value; }
        }

        /// <summary>
        /// Prédiction sur le score de l'équipe à domicile
        /// </summary>
        [DataMemberAttribute()]
        public byte? TeamHomeBetScore
        {
            get { return _teamHomeBetScore; }
            set { _teamHomeBetScore = value; }
        }

        /// <summary>
        /// Prédiction sur le score de l'équipe à l'extérieur
        /// </summary>
        [DataMemberAttribute()]
        public byte? TeamAwayBetScore
        {
            get { return _teamAwayBetScore; }
            set { _teamAwayBetScore = value; }
        }
        #endregion

        #region Data access
        /// <summary>
        /// Copie l'objet représentant la table "Matchs" de la base de données
        /// en objet "MatchObject"
        /// </summary>
        /// <param name="dataToCopy">Objet à copier</param>
        /// <returns>Objet copié</returns>
        /// <exception cref="ArgumentException">L'objet à copier vaut null</exception>
        public static MatchObject CopyFromDatabaseObject(Matchs dataToCopy)
        {
            if (dataToCopy == null)
            {
                throw new ArgumentException("MatchObject.CopyFromDatabaseObject - dataToCopy can not be null");
            }
            MatchObject match = new MatchObject();
            match.MatchId = dataToCopy.MatchId;
            match.TeamHomeId = dataToCopy.Teams1.TeamId;
            match.TeamAwayId = dataToCopy.Teams.TeamId;
            match.TeamHomeScore = dataToCopy.ScoreHome;
            match.TeamAwayScore = dataToCopy.ScoreAway;
            match.DisplayName = String.Empty;
            if (!String.IsNullOrEmpty(dataToCopy.DisplayName))
            {
                match.DisplayName = dataToCopy.DisplayName.Trim();
            }
            return match;
        }

        /// <summary>
        /// Mets à jour ou crée un match pour un événement.
        /// Mise à jour ou création des identifiants des équipes, des scores, de la date du match et de l'événement associé.
        /// </summary>
        /// <param name="dbContext">Connexion à la base de données</param>
        /// <param name="matchDateUTC">Date du match (UTC)</param>
        /// <param name="homeTeamId">Identifiant de l'équipe à domicile</param>
        /// <param name="awayTeamId">Identifiant de l'équipe à l'extérieur</param>
        /// <param name="homeScore">Score de l'équipe à domicile si le match a été joué</param>
        /// <param name="awayScore">Score de l'équipe à l'extérieur si le match a été joué</param>
        /// <param name="awayScore">Identifiant de l'événement du match</param>
        /// <exception cref="ArgumentException">dbContext vaut null</exception>
        /// <exception cref="UpdateException">Equipe ou événement inconnu</exception>
        public static Matchs AddOrUpdate(MyBetDBEntities dbContext, DateTime matchDateUTC, int homeTeamId, int awayTeamId, byte? homeScore, byte? awayScore, int eventId, bool isMatchOfDay)
        {

            Matchs returnMatch = null;

            // Vérification des préconditions
            if (dbContext == null)
            {
                throw new ArgumentException("MatchObject.AddOrUpdate - dbContext can not be null");
            }

            // Récupération du match s'il existe
            var query = (from match in dbContext.Matchs
                         where match.TeamHomeId == homeTeamId && match.TeamAwayId == awayTeamId && match.EventId == eventId
                         select match);
            Matchs matchs = query.FirstOrDefault();

            if (matchs == null)
            {
                // Création d'un nouveau match
                Matchs newMatch = new Matchs();
                newMatch.Date = matchDateUTC;
                newMatch.TeamHomeId = homeTeamId;
                newMatch.TeamAwayId = awayTeamId;
                newMatch.ScoreHome = homeScore;
                newMatch.ScoreAway = awayScore;
                newMatch.EventId = eventId;
                if (isMatchOfDay)
                {
                    newMatch.DisplayName = "1";
                }
                else
                {
                    newMatch.DisplayName = "";
                }
                dbContext.Matchs.AddObject(newMatch);
                returnMatch = newMatch;
            }
            else
            {
                // Mise à jour d'un match
                matchs.Date = matchDateUTC;
                matchs.ScoreHome = homeScore;
                matchs.ScoreAway = awayScore;
                if (isMatchOfDay)
                {
                    matchs.DisplayName = "1";
                }
                else
                {
                    matchs.DisplayName = "";
                }
                returnMatch = matchs;
            }

            return returnMatch;
        }

        /// <summary>
        /// Renvoie la liste de tous les matchs associés à un événement
        /// </summary>
        /// <param name="dbContext">Connexion à la base de données</param>
        /// <param name="eventId">Identifiant de l'événement</param>
        /// <returns>Liste des matchs</returns>
        /// <exception cref="ArgumentException">dbContext vaut null ou événement inconnu</exception>
        public static List<MatchObject> GetMatchsFromEvent(MyBetDBEntities dbContext, int eventId)
        {
            // Vérification des préconditions
            if (dbContext == null)
            {
                throw new ArgumentException("MatchObject.GetMatchsFromEvent - dbContext can not be null");
            }

            List<MatchObject> retList = new List<MatchObject>();
            Events dday = EventObject.GetEventFromDatabase(dbContext, eventId);
            if (dday == null)
            {
                // Evenement inconnu en base de données
                throw new ArgumentException("MatchObject.GetMatchsFromEvent - Unknown event");
            }

            // Création de la liste des MatchObject
            foreach (Matchs match in dday.Matchs)
            {
                MatchObject m;
                m = MatchObject.CopyFromDatabaseObject(match);
                m.DayNumber = dday.DayNumber;
                retList.Add(m);
            }
            return retList;

        }

        /// <summary>
        /// Renvoie la liste des noms des équipes associées aux identifiants des matchs passés en paramètre.
        /// </summary>
        /// <param name="dbContext">Connection à la base de données</param>
        /// <param name="matchId">Liste des identifiants des matchs</param>
        /// <returns>Liste des noms d'équipes</returns>
        public static List<MatchInfo> GetMatchsInfos(MyBetDBEntities dbContext, List<int> matchId)
        {
            // Vérification des préconditions
            if (dbContext == null)
            {
                throw new ArgumentException("MatchObject.AddOrUpdate - dbContext can not be null");
            }
            
            // Test s'il y a au moins un match à traiter
            if ((matchId==null) || (matchId.Count==0))
            {
                return null;
            }
            
            // Récupération des matchs
            StringBuilder clauseWhere = new StringBuilder();
            ParieurPro.DAL.Util.DatabaseHelper.GetInSQLFromObject(ref clauseWhere,"Matchs.MatchId",matchId);
            IEnumerable<MatchInfo> matchInfoResults = dbContext.ExecuteStoreQuery<MatchInfo>
                (String.Format(@"select Matchs.MatchId, Teams1.Name as TeamHomeName, Teams2.Name as TeamAwayName from Matchs
                                 left join Teams Teams1 ON Matchs.TeamHomeId = Teams1.TeamId
                                 left join Teams Teams2 ON Matchs.TeamAwayId = Teams2.TeamId
                                 where {0} order by Matchs.MatchId;", clauseWhere.ToString()));

            // Renvoi la liste
            return matchInfoResults.ToList();
        }

        #endregion
    }

    [Serializable()]
    public class MatchInfo
    {
        /// <summary>
        /// Identifiant unique du match
        /// </summary>
        [Key()]
        [DataMemberAttribute()]
        public int MatchId
        {
            get;
            set;
        }

        [DataMemberAttribute()]
        public string TeamHomeName
        {
            get;
            set;
        }

        [DataMemberAttribute()]
        public string TeamAwayName
        {
            get;
            set;
        }

    }

}